//! 作用域规则 (Scoping Rules)
//!
//! 作用域规则在 Rust 中非常重要，它们与所有权（ownership）、借用（borrowing）和生命周期（lifetimes）
//! 密切相关。理解这些概念对于编写安全且高效的 Rust 代码至关重要。

/// 1. 所有权 (Ownership)
///
/// Rust 通过所有权机制来管理内存，避免了垃圾回收的开销。
/// 每个值都有一个所有者，同一时间只能有一个所有者。
/// 当所有者离开作用域时，值会被自动销毁。
pub fn ownership() {
    println!("=== 所有权 (Ownership) ===");

    // s 的作用域开始
    let s = String::from("hello"); // 从这里开始，s 拥有这个 String 对象
    println!("字符串: {}", s);
    // s 的作用域结束，String 对象被销毁（drop 被调用）

    // 如果我们尝试在这里使用 s，会编译错误
    // println!("字符串: {}", s); // 错误：value borrowed here after move
}

/// 2. 移动语义 (Move Semantics)
///
/// 对于堆分配的数据，赋值会转移所有权而不是复制
pub fn move_semantics() {
    println!("\n=== 移动语义 (Move Semantics) ===");

    let s1 = String::from("hello");
    let s2 = s1; // s1 的所有权被移动到 s2

    println!("s2: {}", s2);
    // println!("s1: {}", s1); // 错误：value borrowed here after move
}

/// 3. 克隆 (Clone)
///
/// 如果确实需要深度复制堆数据，可以使用 clone 方法
pub fn clone_example() {
    println!("\n=== 克隆 (Clone) ===");

    let s1 = String::from("hello");
    let s2 = s1.clone(); // 深度复制

    println!("s1: {}, s2: {}", s1, s2);
}

/// 4. 拷贝 (Copy)
///
/// 对于栈上的数据，Rust 默认进行拷贝
pub fn copy_example() {
    println!("\n=== 拷贝 (Copy) ===");

    let x = 5;
    let y = x; // 拷贝，不是移动

    println!("x: {}, y: {}", x, y);
}

/// 5. 借用 (Borrowing)
///
/// 通过引用可以借用值而不获取所有权
pub fn borrowing() {
    println!("\n=== 借用 (Borrowing) ===");

    let s1 = String::from("hello");
    let len = calculate_length(&s1); // 借用 s1
    println!("'{}' 的长度是 {}", s1, len);
}

/// 计算字符串长度的函数，使用引用避免获取所有权
fn calculate_length(s: &String) -> usize {
    s.len()
    // s 在这里离开作用域，但由于没有所有权，不会被销毁
}

/// 6. 可变借用 (Mutable Borrowing)
///
/// 可以通过可变引用修改借用的值
pub fn mutable_borrowing() {
    println!("\n=== 可变借用 (Mutable Borrowing) ===");

    let mut s = String::from("hello");
    change(&mut s); // 可变借用
    println!("修改后的字符串: {}", s);
}

/// 修改字符串的函数
fn change(s: &mut String) {
    s.push_str(", world");
}

/// 7. 借用规则
///
/// Rust 的借用规则：
/// 1. 在任意给定时刻，只能拥有一个可变引用或任意数量的不可变引用
/// 2. 引用必须总是有效的
pub fn borrowing_rules() {
    println!("\n=== 借用规则 ===");

    let mut s = String::from("hello");

    let r1 = &s; // 第一个不可变引用
    let r2 = &s; // 第二个不可变引用
    println!("{} and {}", r1, r2);
    // r1 和 r2 在这里不再使用

    let r3 = &mut s; // 可变引用
    println!("可变引用: {}", r3);
}

/// 8. 悬垂引用 (Dangling References)
///
/// Rust 确保引用永远不会悬空
pub fn dangling_references() {
    println!("\n=== 悬垂引用 (Dangling References) ===");

    // 下面的代码会编译失败，因为 Rust 会防止悬垂引用
    /*
    fn dangle() -> &String { // 错误：missing lifetime specifier
        let s = String::from("hello");
        &s // 返回对 s 的引用，但 s 在函数结束时会被销毁
    }
    */

    // 正确的做法是返回 String 本身
    fn no_dangle() -> String {
        let s = String::from("hello");
        s // 所有权被移动到调用者
    }

    let s = no_dangle();
    println!("非悬垂引用: {}", s);
}

/// 9. 切片 (Slices)
///
/// 切片是引用的一种形式，它不拥有数据，而是引用集合中的一段连续元素
pub fn slices() {
    println!("\n=== 切片 (Slices) ===");

    let s = String::from("hello world");

    // 字符串切片
    let hello = &s[0..5];
    let world = &s[6..11];

    println!("字符串切片: '{}' 和 '{}'", hello, world);

    // 数组切片
    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3];

    println!("数组切片: {:?}", slice);
}

/// 主演示函数
pub fn demonstrate_scoping_rules() {
    ownership();
    move_semantics();
    clone_example();
    copy_example();
    borrowing();
    mutable_borrowing();
    borrowing_rules();
    dangling_references();
    slices();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ownership() {
        let s = String::from("test");
        assert_eq!(s, "test");
        // 验证所有权概念（编译时检查）
    }

    #[test]
    fn test_move_semantics() {
        let s1 = String::from("hello");
        let s2 = s1;
        assert_eq!(s2, "hello");
        // s1 不再可用（编译时检查）
    }

    #[test]
    fn test_copy() {
        let x = 5;
        let y = x;
        assert_eq!(x, 5);
        assert_eq!(y, 5);
    }

    #[test]
    fn test_borrowing() {
        let s = String::from("hello");
        let len = calculate_length(&s);
        assert_eq!(len, 5);
    }

    #[test]
    fn test_mutable_borrowing() {
        let mut s = String::from("hello");
        change(&mut s);
        assert_eq!(s, "hello, world");
    }

    #[test]
    fn test_slices() {
        let s = String::from("hello world");
        let hello = &s[0..5];
        let world = &s[6..11];
        assert_eq!(hello, "hello");
        assert_eq!(world, "world");

        let a = [1, 2, 3, 4, 5];
        let slice = &a[1..3];
        assert_eq!(slice, &[2, 3]);
    }
}
